import Data.Char (isDigit)

splitAll :: Eq a => [a] -> [a] -> [[a]]
splitAll _ [] = []
splitAll delims xs = 
    token : splitAll delims rest
    where
        isDelimiter = (`elem` delims)
        token       = takeWhile (not . isDelimiter) xs
        rest        = dropWhile isDelimiter $ dropWhile (not . isDelimiter) xs

type Value = Int
type Ticket = [Value]
type Range = (Value, Value)

type FeildName = String
data Feild = Feild FeildName (Range, Range) deriving (Show)

type Document = ([Feild], Ticket, [Ticket])

parseTicket :: String -> Ticket
parseTicket = map read . splitAll "," 

-- 43-322
parseRange :: String -> Range
parseRange string = (low, heigh)
    where
        low = read . takeWhile isDigit $ string
        heigh = read . tail . dropWhile isDigit $ string

-- departure location: 42-322 or 347-954
parseFeild :: String -> Feild
parseFeild string = Feild name (range1, range2)
    where
        name = takeWhile (/=':') string
        rangeStrings = splitAll " or " 
                     . drop 2 
                     . dropWhile (/=':') $ string

        range1 = parseRange (rangeStrings !! 0)
        range2 = parseRange (rangeStrings !! 1)

parseInput :: String -> Document
parseInput input = (feilds, ticket, tickets)
    where
        tokens = splitAll [""] . lines $ input

        feilds = map parseFeild (tokens !! 0)
        ticket = parseTicket . last $ (tokens !! 1)
        tickets = map parseTicket . tail $ (tokens !! 2)

inRange :: Range -> Value -> Bool
inRange (low, heigh) value = (value >= low) && (value <= heigh)

isFeildValid :: Value -> Feild -> Bool
isFeildValid value (Feild _ (range1,range2)) = 
    (inRange range1 value) || (inRange range2 value)

isFeildsValid :: Value -> [Feild] -> Bool
isFeildsValid value = any (isFeildValid value) 

-- type Document = ([Feild], Ticket, [Ticket])
notValidValues :: Document -> [Value]
notValidValues (feilds, _, tickets) = filter notValid values
    where
        values = foldl (++) [] tickets

        notValid :: Value -> Bool
        notValid v = not $ isFeildsValid v feilds 

main :: IO ()
main = do
    input <- readFile "input.txt"
    print . sum . notValidValues . parseInput $ input